using LiJ.Common.Core;
using LiJ.Common.Core.Enums;
using LiJ.Common.Extention;
using LiJ.Framework.Msg.Mos;
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;

namespace LiJ.Framework.Msg
{
	/// <summary>
	///   消息处理的基类
	/// </summary>
	public class WxMsgBaseHandler : BaseConfigProvider<WxMsgConfig, WxMsgBaseHandler>
	{
		/// <summary>
		/// 消息处理基类
		/// </summary>
		/// <param name="config"></param>
		protected WxMsgBaseHandler(WxMsgConfig config = null)
			: base(config)
		{
			base.ModuleName = WxMsgConfigProvider.ModuleName;
		}

		/// <summary>
		///  服务器验证
		/// </summary>
		/// <param name="signature"></param>
		/// <param name="timestamp"></param>
		/// <param name="nonce"></param>
		/// <param name="echostr"></param>
		/// <returns></returns>
		public ResultMo<string> CheckServerValid(string signature, string timestamp, string nonce, string echostr)
		{
			ResultMo<string> resultMo = WxMsgHelper.CheckSignature(base.ApiConfig.Token, signature, timestamp, nonce).ConvertToResultOnly<string>();
			resultMo.Data = (resultMo.IsSuccess() ? echostr : string.Empty);
			return resultMo;
		}

		/// <summary>
		///    消息处理入口
		/// </summary>
		/// <param name="reqStream">内容的数据流</param>
		/// <param name="signature">签名信息</param>
		/// <param name="timestamp">时间戳</param>
		/// <param name="nonce">随机字符创</param>
		/// <param name="echostr">验证服务器参数，如果存在则只进行签名验证，并将在结果data中返回</param>
		/// <returns>消息结果，Data为响应微信数据，如果出错Message为错误信息</returns>
		public ResultMo<string> Process(Stream reqStream, string signature, string timestamp, string nonce, string echostr)
		{
			string contentXml = default(string);
			using (StreamReader streamReader = new StreamReader(reqStream))
			{
				contentXml = streamReader.ReadToEnd();
			}
			return this.Process(contentXml, signature, timestamp, nonce, echostr);
		}

		/// <summary>
		/// 消息处理入口
		/// </summary>
		/// <param name="contentXml">内容信息</param>
		/// <param name="signature">签名信息</param>
		/// <param name="timestamp">时间戳</param>
		/// <param name="nonce">随机字符创</param>
		/// <param name="echostr">验证服务器参数，如果存在则只进行签名验证，并将在结果data中返回</param>
		/// <returns>消息结果，Data为响应微信数据，如果出错Message为错误信息</returns>
		public ResultMo<string> Process(string contentXml, string signature, string timestamp, string nonce, string echostr)
		{
			if (!string.IsNullOrEmpty(echostr))
			{
				return this.CheckServerValid(signature, timestamp, nonce, echostr);
			}
			ResultMo<string> resultMo = this.PrepareExecute(contentXml, signature, timestamp, nonce);
			if (!resultMo.IsSuccess())
			{
				return resultMo.ConvertToResultOnly<string>();
			}
			ResultMo<WxMsgContext> resultMo2 = this.Execute(resultMo.Data);
			if (!resultMo2.IsSuccess())
			{
				return resultMo2.ConvertToResultOnly<string>();
			}
			string text = resultMo2.Data.ReplyMsg.ToReplyXml();
			if (base.ApiConfig.SecurityType != 0 && !string.IsNullOrEmpty(resultMo2.Data.ReplyMsg.MsgType))
			{
				return WxMsgHelper.EncryptMsg(text, base.ApiConfig);
			}
			return new ResultMo<string>(text);
		}

		/// <summary>
		/// 核心执行方法 过程中的 委托方代码执行
		/// </summary>
		/// <param name="recMsgXml">传入消息的xml</param>
		/// <returns></returns>
		protected virtual ResultMo<WxMsgContext> Execute(string recMsgXml)
		{
		    var dictionary = WxMsgHelper.ChangXmlToDir(recMsgXml, out var xmlDocument);
		    dictionary.TryGetValue("MsgType", out var text);
			string eventName = null;
			if (text == "event" && !dictionary.TryGetValue("Event", out eventName))
			{
				return new ResultMo<WxMsgContext>(ResultTypes.ParaError, "事件消息数据中未发现 事件类型（Event）字段！");
			}
			WxMsgProcessor wxMsgProcessor = this.GetBasicMsgProcessor(text, eventName);
			if (!((wxMsgProcessor != null) ? new bool?(wxMsgProcessor.CanExecute) : null).HasValue)
			{
				wxMsgProcessor = this.GetCustomProcessor(text, eventName, dictionary);
				bool? nullable = (wxMsgProcessor != null) ? new bool?(wxMsgProcessor.CanExecute) : null;
				if (!nullable.HasValue)
				{
					wxMsgProcessor = WxMsgBaseHandler.GetRegProcessor(text, eventName);
				}
			}
			object wxMsgContext;
			if (wxMsgProcessor == null || !wxMsgProcessor.CanExecute)
			{
				wxMsgContext = this.ExecuteProcessor(xmlDocument, dictionary, new WxBaseRecMsg(), null);
			}
			else
			{
				var recMsgXml2 = xmlDocument;
				var recMsgDirs = dictionary;
				var recMsg = wxMsgProcessor.CreateNewInstance();
				var wxMsgProcessor2 = wxMsgProcessor;
				wxMsgContext = this.ExecuteProcessor(recMsgXml2, recMsgDirs, recMsg, wxMsgProcessor2.Execute);
			}
			var wxMsgContext2 = (WxMsgContext)wxMsgContext;
			this.ExecuteEnd(wxMsgContext2);
			return new ResultMo<WxMsgContext>(wxMsgContext2);
		}

		/// <summary>
		///  执行过程中，业务执行前
		///     如果对 ReplyMsg 赋值，则后续
		/// </summary>
		/// <param name="context"></param>
		protected virtual void Executing(WxMsgContext context)
		{
		}

		/// <summary>
		///   执行处理未知消息
		/// </summary>
		/// <returns></returns>
		protected virtual WxBaseReplyMsg ExecuteUnknowProcessor(WxBaseRecMsg msg)
		{
			return null;
		}

		/// <summary>
		///  执行结束方法
		/// </summary>
		/// <param name="msgContext"></param>
		protected virtual void ExecuteEnd(WxMsgContext msgContext)
		{
		}

		/// <summary>
		///  获取消息处理Processor
		///   【返回对象需继承：WxMsgProcessor&lt;TRecMsg&gt;】
		/// </summary>
		/// <param name="msgType">消息类型</param>
		/// <param name="eventName">事件名称</param>
		/// <param name="msgInfo">对应消息的键值对</param>
		/// <returns>WxMsgProcessor&lt;TRecMsg&gt;或其子类，如果没有定义对应的消息类型，返回Null即可</returns>
		protected virtual WxMsgProcessor GetCustomProcessor(string msgType, string eventName, IDictionary<string, string> msgInfo)
		{
			return null;
		}

		internal virtual WxMsgProcessor GetBasicMsgProcessor(string msgType, string eventName)
		{
			return null;
		}

		private static WxMsgProcessor GetRegProcessor(string msgType, string eventName)
		{
			return WxMsgConfigProvider.GetProcessor((msgType == "event") ? ("event_" + (eventName ?? string.Empty)) : msgType);
		}

		/// <summary>
		/// 核心执行 过程的  验签和解密
		/// </summary>
		/// <param name="recXml">消息内容</param>
		/// <param name="signature">微信加密签名</param>
		/// <param name="timestamp">时间戳</param>
		/// <param name="nonce">随机数</param>
		/// <returns>验证结果及相应的消息内容体 （如果加密模式，返回的是解密后的明文）</returns>
		private ResultMo<string> PrepareExecute(string recXml, string signature, string timestamp, string nonce)
		{
			if (string.IsNullOrEmpty(recXml))
			{
				return new ResultMo<string>(ResultTypes.ObjectNull, "接收的消息体为空！");
			}
			ResultMo resultMo = WxMsgHelper.CheckSignature(base.ApiConfig.Token, signature, timestamp, nonce);
			if (!resultMo.IsSuccess())
			{
				return resultMo.ConvertToResultOnly<string>();
			}
			if (base.ApiConfig.SecurityType == WxSecurityType.None)
			{
				return new ResultMo<string>(recXml);
			}

		    var dictionary = WxMsgHelper.ChangXmlToDir(recXml, out _);
		    if (dictionary != null && dictionary.TryGetValue("Encrypt", out var text) && !string.IsNullOrEmpty(text))
			{
				return new ResultMo<string>(Cryptography.WxAesDecrypt(text, base.ApiConfig.EncodingAesKey));
			}
			return new ResultMo<string>(ResultTypes.ObjectNull, "加密消息为空");
		}

		/// <summary>
		///  执行具体消息处理委托
		/// </summary>
		/// <returns></returns>
		private WxMsgContext ExecuteProcessor<TRecMsg>(XmlDocument recMsgXml, IDictionary<string, string> recMsgDirs, TRecMsg recMsg, Func<TRecMsg, WxBaseReplyMsg> func) where TRecMsg : WxBaseRecMsg, new()
		{
			if (recMsg == null)
			{
				recMsg = new TRecMsg();
			}
			recMsg.LoadMsgDirs(recMsgDirs);
			recMsg.RecMsgXml = recMsgXml;
			WxMsgContext wxMsgContext = new WxMsgContext
			{
				RecMsg = (WxBaseRecMsg)(object)recMsg
			};
			this.Executing(wxMsgContext);
			if (wxMsgContext.ReplyMsg == null)
			{
				wxMsgContext.ReplyMsg = ((func != null) ? func(recMsg) : null);
			}
			if (wxMsgContext.ReplyMsg == null)
			{
				wxMsgContext.ReplyMsg = (this.ExecuteUnknowProcessor((WxBaseRecMsg)(object)recMsg) ?? WxNoneReplyMsg.None);
			}
			wxMsgContext.ReplyMsg.ToUserName = recMsg.FromUserName;
			wxMsgContext.ReplyMsg.FromUserName = recMsg.ToUserName;
			wxMsgContext.ReplyMsg.CreateTime = DateTime.Now.ToLocalSeconds();
			return wxMsgContext;
		}

		/// <inheritdoc />
		protected override WxMsgConfig GetDefaultConfig()
		{
			return WxMsgConfigProvider.DefaultConfig;
		}
	}
}
